﻿using System;
using System.Buffers.Binary;

namespace WholeSlideImageLibrary.Formats.OptimizedPyramidTiledImage
{
    public readonly struct FileContentRegion : IEquatable<FileContentRegion>
    {
        public FileContentRegion(long offset, int length)
        {
            Offset = offset;
            Length = length;
        }

        public FileContentRegion(long offset, int length, long totalFileSize)
        {
            Offset = offset < 0 ? totalFileSize + offset : offset;
            Length = length;
        }

        public const int MarshalSize = 12;

        public long Offset { get; }
        public int Length { get; }

        public bool IsEmpty => Offset == 0 && Length == 0;

        public static bool TryParse(ReadOnlySpan<byte> buffer, long totalFileSize, out FileContentRegion tilePosition)
        {
            if (buffer.Length < MarshalSize)
            {
                tilePosition = default;
                return false;
            }

            tilePosition = new FileContentRegion(
                offset: BinaryPrimitives.ReadInt64LittleEndian(buffer),
                length: BinaryPrimitives.ReadInt32LittleEndian(buffer.Slice(8)),
                totalFileSize: totalFileSize);
            return true;
        }

        public bool TryWriteTo(Span<byte> destination)
        {
            if (destination.Length < MarshalSize)
            {
                return false;
            }

            BinaryPrimitives.WriteInt64LittleEndian(destination, Offset);
            BinaryPrimitives.WriteInt32LittleEndian(destination.Slice(8), Length);
            return true;
        }

        public override bool Equals(object? obj) => obj is FileContentRegion other && Equals(other);

        public bool Equals(FileContentRegion other) => Offset == other.Offset && Length == other.Length;

        public override int GetHashCode() => HashCode.Combine(Offset, Length);

        public static bool operator ==(FileContentRegion left, FileContentRegion right) => left.Equals(right);

        public static bool operator !=(FileContentRegion left, FileContentRegion right) => !left.Equals(right);
    }
}
